package org.ljdp.util;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

public class PicResize {
	private int width;
	private int height;
	private int scaleWidth;
	double support = (double) 3.0;
	double PI = (double) 3.14159265358978;
	double[] contrib;
	double[] normContrib;
	double[] tmpContrib;
	int startContrib, stopContrib;
	int nDots;
	int nHalfDots;
 
	public    byte[] resizeImage(byte[] source,String format, int targetW,int targetH) {
		try{
			ByteArrayOutputStream out = new ByteArrayOutputStream();
//			ByteArrayInputStream in = new ByteArrayInputStream(source);    //将b作为输入流；
//			BufferedImage image = PicUtils.getBufferedImage(source);//ImageIO.read(in); 
//			BufferedImage result = imageZoomOut(image,targetW,targetH);
			
			Image image = Toolkit.getDefaultToolkit().createImage(source);
			Image scaleImg = image.getScaledInstance(targetW, targetH, Image.SCALE_SMOOTH);
			BufferedImage result;
			if(format.equalsIgnoreCase("png")) {
				result = PicUtils.getBufferedImage(scaleImg, true);
			} else {
				result = PicUtils.getBufferedImage(scaleImg, false);
			}
			
//			BufferedImage result = new BufferedImage(targetW, targetH, image.getType());
//			Graphics g = result.getGraphics();
//			g.drawImage(image, 0, 0, targetW, targetH, null);
//			g.dispose();
			
			ImageIO.write(result,format,out);
			return out.toByteArray();
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;

	}
	 
	
	/*
	 * 根据尺寸图片居中裁剪
	 */
	public   byte[] cutCenterImage(byte[] source, String format, Integer size) throws IOException {

		try {
			
			
			if(size == null){
				size = 400;//图片裁剪尺寸
			}
            
			 format = PicUtils.getImageType(source);
			Iterator iterator = ImageIO.getImageReadersByFormatName(format);
			ImageReader reader = (ImageReader) iterator.next();
			 
			 
			ByteArrayInputStream bis = new ByteArrayInputStream(source);

			
			ImageInputStream iis = ImageIO.createImageInputStream(bis);
			reader.setInput(iis, true);

			ImageReadParam param = reader.getDefaultReadParam();
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			
			//ByteArrayInputStream bis = new ByteArrayInputStream(source);    //将b作为输入流；
			BufferedImage image = PicUtils.getBufferedImage(source);//javax.imageio.ImageIO.read(bis);
			int colorSpaceType = image.getColorModel().getColorSpace().getType(); 
            
			if (colorSpaceType == ColorSpace.TYPE_CMYK) 
            { 
                BufferedImage rgbImage = 
                    new BufferedImage( 
                        image.getWidth(), image.getHeight(), BufferedImage.TYPE_3BYTE_BGR); 
                ColorConvertOp op = new ColorConvertOp(null); 
                op.filter(image, rgbImage); 
 
                image = rgbImage;
            } 

//			Rectangle rect = new Rectangle((image.getWidth() - w) / 2, (image.getHeight() - h) / 2, w, h);
//			param.setSourceRegion(rect);
//			
//			BufferedImage result = reader.read(0,param);
//			
			
			int rw = image.getWidth();
			int rh = image.getHeight();
			if(rw == rh){
				if(rw>size){
					return resizeImage(source,format,size,size);
				}
				return source;
			}
			if(rw>rh)rw = rh;
			if(rh>rw)rh = rw;
			
			ImageFilter  cropFilter = new CropImageFilter((image.getWidth() - rw) / 2, (image.getHeight() - rh) / 2, rw, rh);
			Image  img = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(image.getSource(), cropFilter));
            BufferedImage tag = new BufferedImage(rw, rh,colorSpaceType);
            Graphics g = tag.getGraphics();
            g.drawImage(img, 0, 0, null); // 绘制截取后的图
            g.dispose();

			ImageIO.write(tag, format, out);
			byte[] ret = out.toByteArray();
			if(rw == rh){
				if(rw>size){
					return resizeImage(ret,format,size,size);
				}
				 
			}
			
			return ret;
	    
 

	        
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	      
  
	 }
	
	/**
	 * Start: Use Lanczos filter to replace the original algorithm for image
	 * scaling. Lanczos improves quality of the scaled image modify by :blade
	 * */
	public   BufferedImage imageZoomOut(BufferedImage srcBufferImage, int w, int h) {
		width = srcBufferImage.getWidth();
		height = srcBufferImage.getHeight();
		scaleWidth = w;
 
		if (DetermineResultSize(w, h) == 1) {
			return srcBufferImage;
		}
		CalContrib();
		BufferedImage pbOut = HorizontalFiltering(srcBufferImage, w);
		BufferedImage pbFinalOut = VerticalFiltering(pbOut, h);
		return pbFinalOut;
	}
 
	/**
	 * 决定图像尺寸
	 * */
	private int DetermineResultSize(int w, int h) {
		double scaleH, scaleV;
		scaleH = (double) w / (double) width;
		scaleV = (double) h / (double) height;
		// 需要判断一下scaleH，scaleV，不做放大操作
		if (scaleH >= 1.0 && scaleV >= 1.0) {
			return 1;
		}
		return 0;
 
	} // end of DetermineResultSize()
 
	private double Lanczos(int i, int inWidth, int outWidth, double Support) {
		double x;
 
		x = (double) i * (double) outWidth / (double) inWidth;
 
		return Math.sin(x * PI) / (x * PI) * Math.sin(x * PI / Support)
				/ (x * PI / Support);
 
	} // end of Lanczos()
 
	//
	// Assumption: same horizontal and vertical scaling factor
	//
	private void CalContrib() {
		nHalfDots = (int) ((double) width * support / (double) scaleWidth);
		nDots = nHalfDots * 2 + 1;
		try {
			contrib = new double[nDots];
			normContrib = new double[nDots];
			tmpContrib = new double[nDots];
		} catch (Exception e) {
			System.out.println("init   contrib,normContrib,tmpContrib " + e);
		}
 
		int center = nHalfDots;
		contrib[center] = 1.0;
 
		double weight = 0.0;
		int i = 0;
		for (i = 1; i <= center; i++) {
			contrib[center + i] = Lanczos(i, width, scaleWidth, support);
			weight += contrib[center + i];
		}
 
		for (i = center - 1; i >= 0; i--) {
			contrib[i] = contrib[center * 2 - i];
		}
 
		weight = weight * 2 + 1.0;
 
		for (i = 0; i <= center; i++) {
			normContrib[i] = contrib[i] / weight;
		}
 
		for (i = center + 1; i < nDots; i++) {
			normContrib[i] = normContrib[center * 2 - i];
		}
	} // end of CalContrib()
 
	// 处理边缘
	private void CalTempContrib(int start, int stop) {
		double weight = 0;
 
		int i = 0;
		for (i = start; i <= stop; i++) {
			weight += contrib[i];
		}
 
		for (i = start; i <= stop; i++) {
			tmpContrib[i] = contrib[i] / weight;
		}
 
	} // end of CalTempContrib()
 
	private int GetRedValue(int rgbValue) {
		int temp = rgbValue & 0x00ff0000;
		return temp >> 16;
	}
 
	private int GetGreenValue(int rgbValue) {
		int temp = rgbValue & 0x0000ff00;
		return temp >> 8;
	}
 
	private int GetBlueValue(int rgbValue) {
		return rgbValue & 0x000000ff;
	}
 
	private int ComRGB(int redValue, int greenValue, int blueValue) {
 
		return (redValue << 16) + (greenValue << 8) + blueValue;
	}
 
	// 行水平滤波
	private int HorizontalFilter(BufferedImage bufImg, int startX, int stopX,
			int start, int stop, int y, double[] pContrib) {
		double valueRed = 0.0;
		double valueGreen = 0.0;
		double valueBlue = 0.0;
		int valueRGB = 0;
		int i, j;
 
		for (i = startX, j = start; i <= stopX; i++, j++) {
			valueRGB = bufImg.getRGB(i, y);
 
			valueRed += GetRedValue(valueRGB) * pContrib[j];
			valueGreen += GetGreenValue(valueRGB) * pContrib[j];
			valueBlue += GetBlueValue(valueRGB) * pContrib[j];
		}
 
		valueRGB = ComRGB(Clip((int) valueRed), Clip((int) valueGreen),
				Clip((int) valueBlue));
		return valueRGB;
 
	} // end of HorizontalFilter()
 
	// 图片水平滤波
	private BufferedImage HorizontalFiltering(BufferedImage bufImage, int iOutW) {
		int dwInW = bufImage.getWidth();
		int dwInH = bufImage.getHeight();
		int value = 0;
		BufferedImage pbOut = new BufferedImage(iOutW, dwInH,
				BufferedImage.TYPE_INT_RGB);
 
		for (int x = 0; x < iOutW; x++) {
 
			int startX;
			int start;
			int X = (int) (((double) x) * ((double) dwInW) / ((double) iOutW) + 0.5);
			int y = 0;
 
			startX = X - nHalfDots;
			if (startX < 0) {
				startX = 0;
				start = nHalfDots - X;
			} else {
				start = 0;
			}
 
			int stop;
			int stopX = X + nHalfDots;
			if (stopX > (dwInW - 1)) {
				stopX = dwInW - 1;
				stop = nHalfDots + (dwInW - 1 - X);
			} else {
				stop = nHalfDots * 2;
			}
 
			if (start > 0 || stop < nDots - 1) {
				CalTempContrib(start, stop);
				for (y = 0; y < dwInH; y++) {
					value = HorizontalFilter(bufImage, startX, stopX, start,
							stop, y, tmpContrib);
					pbOut.setRGB(x, y, value);
				}
			} else {
				for (y = 0; y < dwInH; y++) {
					value = HorizontalFilter(bufImage, startX, stopX, start,
							stop, y, normContrib);
					pbOut.setRGB(x, y, value);
				}
			}
		}
 
		return pbOut;
 
	} // end of HorizontalFiltering()
 
	private int VerticalFilter(BufferedImage pbInImage, int startY, int stopY,
			int start, int stop, int x, double[] pContrib) {
		double valueRed = 0.0;
		double valueGreen = 0.0;
		double valueBlue = 0.0;
		int valueRGB = 0;
		int i, j;
 
		for (i = startY, j = start; i <= stopY; i++, j++) {
			valueRGB = pbInImage.getRGB(x, i);
 
			valueRed += GetRedValue(valueRGB) * pContrib[j];
			valueGreen += GetGreenValue(valueRGB) * pContrib[j];
			valueBlue += GetBlueValue(valueRGB) * pContrib[j];
			// System.out.println(valueRed+ "-> "+Clip((int)valueRed)+ " <- ");
			//
			// System.out.println(valueGreen+ "-> "+Clip((int)valueGreen)+
			// " <- ");
			// System.out.println(valueBlue+ "-> "+Clip((int)valueBlue)+ " <- "+
			// "--> ");
		}
 
		valueRGB = ComRGB(Clip((int) valueRed), Clip((int) valueGreen),
				Clip((int) valueBlue));
		// System.out.println(valueRGB);
		return valueRGB;
 
	} // end of VerticalFilter()
 
	private BufferedImage VerticalFiltering(BufferedImage pbImage, int iOutH) {
		int iW = pbImage.getWidth();
		int iH = pbImage.getHeight();
		int value = 0;
		BufferedImage pbOut = new BufferedImage(iW, iOutH,
				BufferedImage.TYPE_INT_RGB);
 
		for (int y = 0; y < iOutH; y++) {
 
			int startY;
			int start;
			int Y = (int) (((double) y) * ((double) iH) / ((double) iOutH) + 0.5);
 
			startY = Y - nHalfDots;
			if (startY < 0) {
				startY = 0;
				start = nHalfDots - Y;
			} else {
				start = 0;
			}
 
			int stop;
			int stopY = Y + nHalfDots;
			if (stopY > (int) (iH - 1)) {
				stopY = iH - 1;
				stop = nHalfDots + (iH - 1 - Y);
			} else {
				stop = nHalfDots * 2;
			}
 
			if (start > 0 || stop < nDots - 1) {
				CalTempContrib(start, stop);
				for (int x = 0; x < iW; x++) {
					value = VerticalFilter(pbImage, startY, stopY, start, stop,
							x, tmpContrib);
					pbOut.setRGB(x, y, value);
				}
			} else {
				for (int x = 0; x < iW; x++) {
					value = VerticalFilter(pbImage, startY, stopY, start, stop,
							x, normContrib);
					pbOut.setRGB(x, y, value);
				}
			}
 
		}
 
		return pbOut;
 
	} // end of VerticalFiltering()
 
	int Clip(int x) {
		if (x < 0)
			return 0;
		if (x > 255)
			return 255;
		return x;
	}
	
//	public static void main(String[] args) {
//		try {
//			byte[] contents = FileUtils.readFileToByteArray(new File("C:/Users/Administrator/Desktop/temp/p1.png"));
//			
//			PicResize pr = new PicResize();
//			byte[] resize = pr.resizeImage(contents, "png", 350, 100);
//			
//			FileUtils.writeByteArrayToFile(new File("C:/Users/Administrator/Desktop/temp/test.png"), resize);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		
//	}
}
